home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
MacFormat 1995 January
/
macformat-020.iso
/
Shareware City
/
Developers
/
CWASTE folder
/
WASTE2.c
< prev
next >
Encoding:
Amiga
Atari
Commodore
DOS
FM Towns/JPY
Macintosh
Macintosh JP
NeXTSTEP
RISC OS/Acorn
Shift JIS
UTF-8
Wrap
Text File
|
1994-07-20
|
28.2 KB
|
1,166 lines
|
[
TEXT/MPCC
]
// { WASTE PROJECT: }
// { Unit Two: Creation & Destruction; Getting and Setting Variables &c. }
// { Copyright © 1993-1994 Marco Piovanelli }
// { All Rights Reserved }
// C conversion by Dan Crevier
#include "WASTEIntf.h"
#include <Palettes.h>
#include <QDOffscreen.h>
#include <GestaltEqu.h>
OSErr _WERegisterWithTSM(WEHandle hWE)
{
// { the WE record must be already locked }
WEPtr pWE;
OSType typeList[1];
OSErr err;
pWE = *hWE;
// { do nothing if the Text Services Manager isn't available }
if (BTST(pWE->flags, weFHasTextServices))
{
typeList[0] = kTextService;
err = NewTSMDocument(1, typeList, &pWE->tsmReference, (long)hWE);
if (err != noErr)
{
// { we don't consider it an error if our client application isn't TSM-aware }
if (err != tsmNeverRegisteredErr)
{
goto cleanup;
}
}
}
// { clear result code }
err = noErr;
cleanup:
// { return result code }
return err;
}
pascal void WEStopInlineSession(WEHandle hWE)
{
TSMDocumentID tsmReference;
tsmReference = (*hWE)->tsmReference;
if (tsmReference != nil)
{
FixTSMDocument(tsmReference);
}
}
pascal OSErr WENew(LongRect *destRect, LongRect *viewRect, short flags, WEHandle *hWE)
{
WEPtr pWE;
short allocFlags;
long weFlags;
long response;
Rect r;
OSErr err;
pWE = nil;
weFlags = flags;
allocFlags = kAllocClear;
// { allocate the WE record }
err = _WEAllocate(sizeof(WERec), allocFlags, (Handle *)hWE);
if (err != noErr)
{
goto cleanup;
}
// { lock it down }
HLock((Handle)*hWE);
pWE = **hWE;
// { get active port }
GetPort(&pWE->port);
// { determine whether temporary memory should be used for data structures }
if (BTST(weFlags, weFUseTempMem))
{
allocFlags = allocFlags + kAllocTemp;
}
// { allocate the text handle (initially empty) }
err = _WEAllocate(0, allocFlags, (Handle *)&pWE->hText);
if (err != noErr)
{
goto cleanup;
}
// { allocate the line array }
err = _WEAllocate(2 * sizeof(LineRec), allocFlags, (Handle *)&pWE->hLines);
if (err != noErr)
{
goto cleanup;
}
// { allocate the style table }
err = _WEAllocate(sizeof(StyleTableElement), allocFlags, (Handle *)&pWE->hStyles);
if (err != noErr)
{
goto cleanup;
}
// { allocate the run array }
err = _WEAllocate(2 * sizeof(RunArrayElement), allocFlags, (Handle *)&pWE->hRuns);
if (err != noErr)
{
goto cleanup;
}
// { check for the presence of various system software features }
// { determine whether Color QuickDraw is available }
if (Gestalt(gestaltQuickdrawVersion, &response) == noErr)
{
if (response >= gestalt8BitQD)
{
BSET(weFlags, weFHasColorQD);
}
}
// { determine whether the Text Services manager is available }
if (Gestalt(gestaltTSMgrVersion, &response) == noErr)
{
BSET(weFlags, weFHasTextServices);
}
// { determine if there are any non-Roman scripts enabled }
if (GetEnvirons(smEnabled) > 1)
{
BSET(weFlags, weFNonRoman);
}
// { determine whether a double-byte script is installed }
if (GetEnvirons(smDoubleByte) != 0)
{
BSET(weFlags, weFDoubleByte);
}
// { initialize miscellaneous fields of the WE record }
pWE->nLines = 1;
pWE->nStyles = 1;
pWE->nRuns = 1;
pWE->viewRect = *viewRect;
pWE->destRect = *destRect;
pWE->flags = weFlags;
pWE->tsmAreaStart = kInvalidOffset;
pWE->tsmAreaEnd = kInvalidOffset;
// { create a region to hold the view rectangle }
pWE->viewRgn = NewRgn();
WELongRectToRect(viewRect, &r);
RectRgn(pWE->viewRgn, &r);
// { initialize the style run array }
(*pWE->hRuns)[1].runStart = 1;
(*pWE->hRuns)[1].styleIndex = -1;
// { initialize the style table }
(*pWE->hStyles)[0].refCount = 1;
// { copy text attributes from the active graphics port }
(*pWE->hStyles)[0].info.runStyle.tsFont = pWE->port->txFont;
(*pWE->hStyles)[0].info.runStyle.tsSize = pWE->port->txSize;
(*pWE->hStyles)[0].info.runStyle.tsFace = ((GrafPtr1)pWE->port)->txFace;
_WEFillFontInfo(pWE->port, &(*pWE->hStyles)[0].info);
if (BTST(weFlags, weFHasColorQD))
{
GetForeColor(&(*pWE->hStyles)[0].info.runStyle.tsColor);
}
// { initialize the line array }
err = WECalText(*hWE);
if (err != noErr)
{
goto cleanup;
}
// { register with the Text Services Manager }
err = _WERegisterWithTSM(*hWE);
if (err != noErr)
{
goto cleanup;
}
// { unlock the WE record }
HUnlock((Handle)*hWE);
// { skip clean-up section }
return noErr;
cleanup:
// { clean up }
if (pWE != nil)
{
_WEForgetHandle((Handle *)&pWE->hText);
_WEForgetHandle((Handle *)&pWE->hLines);
_WEForgetHandle((Handle *)&pWE->hStyles);
_WEForgetHandle((Handle *)&pWE->hRuns);
if (pWE->viewRgn != nil)
{
DisposeRgn(pWE->viewRgn);
}
}
_WEForgetHandle((Handle *)hWE);
return err;
}
pascal void WEDispose(WEHandle hWE)
{
WEPtr pWE;
// { sanity check: make sure WE isn't NIL }
if (hWE == nil)
{
return;
}
// { lock the WE record }
HLock((Handle)hWE);
pWE = *hWE;
// { dispose of auxiliary data structures }
_WEForgetHandle((Handle *)&pWE->hText);
_WEForgetHandle((Handle *)&pWE->hLines);
_WEForgetHandle((Handle *)&pWE->hStyles);
_WEForgetHandle((Handle *)&pWE->hRuns);
DisposeRgn(pWE->viewRgn);
// { dispose of the offscreen graphics world }
if (pWE->offscreenPort != nil)
{
DisposeGWorld((GWorldPtr)pWE->offscreenPort);
}
// { unregister with the Text Services Manager }
if (pWE->tsmReference != nil)
{
DeleteTSMDocument(pWE->tsmReference);
}
// { dispose of the WE record }
DisposeHandle((Handle)hWE);
}
OSErr _WERemoveLine(long lineIndex, WEPtr pWE)
{
OSErr retval;
// { remove the specified element from the line array }
// { do the removal (errors returned by _WERemoveSlot can be safely ignored) }
retval = _WERemoveSlot((Handle)pWE->hLines, lineIndex, sizeof(LineRec));
// { decrement line count }
pWE->nLines = pWE->nLines - 1;
return retval;
}
OSErr InsertLine(long lineIndex, LineRec *theLine, WEPtr pWE)
{
// { insert the specified element in the line array }
OSErr err;
// { do the insertion }
err = _WEInsertSlot((Handle)pWE->hLines, (Ptr)theLine, lineIndex, sizeof(LineRec));
if (err != noErr)
{
return err;
}
// { increment line count }
pWE->nLines = pWE->nLines + 1;
return noErr;
}
void _WEBumpOrigin(long lineIndex, long deltaOrigin, WEPtr pWE)
{
long *pOrigin;
long nLines;
pOrigin = &((*pWE->hLines)[lineIndex].lineOrigin);
// { loop through the line run array adjusting the lineOrigin fields }
nLines = pWE->nLines;
while (lineIndex <= nLines)
{
*pOrigin = *pOrigin + deltaOrigin;
pOrigin = (long *)((long)pOrigin + sizeof(LineRec));
lineIndex = lineIndex + 1;
}
}
long _WEFindLineBreak(long lineStart, WEHandle hWE)
{
// { Find where to break the line beginning at lineStart }
// { the WE record and the text must be already locked }
// { the current graphics port must be already set up correctly }
WEPtr pWE;
Ptr pText;
long offset, breakOffset;
long textLength;
long remainingLength;
long segmentStart, segmentEnd;
long runIndex;
WERunInfo runInfo;
Fixed pixelWidth;
ScriptCode script, previousScript;
pWE = *hWE;
offset = lineStart;
pText = *pWE->hText + offset;
remainingLength = pWE->textLength - offset;
// { find the style run index corresponding to the first segment on this line }
runIndex = _WEOffsetToRun(offset, hWE);
// { initialize pixelWidth to the width of the destination rectangle, as a Fixed quantity }
pixelWidth = BSL(pWE->destRect.right - pWE->destRect.left, 16);
// { STYLE SEGMENT LOOP }
do
{
// { get style run information for the current style run }
_WEGetIndStyle(runIndex, &runInfo, hWE);
runIndex = runIndex + 1;
// { set text attributes in the graphics port }
TextFont(runInfo.runAttrs.runStyle.tsFont);
TextFace(runInfo.runAttrs.runStyle.tsFace);
TextSize(runInfo.runAttrs.runStyle.tsSize);
// { if we're handling multiscript text, keep track of script boundaries }
if (BTST(pWE->flags, weFNonRoman))
{
// { what is the script for this segment? }
script = Font2Script(runInfo.runAttrs.runStyle.tsFont);
// { have we crossed a script run boundary in the middle of a line? }
if ((runInfo.runStart > offset) && (script != previousScript))
{
// { leave behind the all previous segments on this line }
offset = runInfo.runStart;
pText = *pWE->hText + offset;
remainingLength = pWE->textLength - offset;
}
previousScript = script;
} // { if non-Roman }
// { we'll pass textLength as the second parameter to StyledLineBreak }
// { although this parameter is declared as a long, StyledLineBreak uses only }
// { the low word, so make sure it doesn't trespass the 32,767 byte threshold! }
textLength = _WEPinInRange(remainingLength, 0, SHRT_MAX);
// { calculate segmentStart and segmentEnd relative to offset }
segmentStart = _WEPinInRange(runInfo.runStart - offset, 0, textLength);
segmentEnd = _WEPinInRange(runInfo.runEnd - offset, 0, textLength);
// { set breakOffset to a non-zero value for the first script run on the line, }
// { set it to zero for all subsequent script runs }
breakOffset = (offset == lineStart);
// { keep looping until StyledLineBreak detects a break or we reach the end of the text }
} while ((StyledLineBreak(pText, textLength, segmentStart, segmentEnd, 0, &pixelWidth, &breakOffset)
== smBreakOverflow) && (segmentEnd < remainingLength));
// { return the offset from lineStart to the break point }
return (offset - lineStart) + breakOffset;
}
void _WECalcHeights(long rangeStart, long rangeEnd, short *lineAscent, short *lineDescent,
WEHandle hWE)
{
// { Find the maximum ascent and descent values between rangeStart and rangeEnd }
// { the WE record must be already locked }
// { the current graphics port must be already set up correctly }
long runIndex;
WERunInfo runInfo;
short runAscent, runDescent;
*lineAscent = 1;
*lineDescent = 1;
// { find the style run index corresponding to the first segment on this line }
runIndex = _WEOffsetToRun(rangeStart, hWE);
// { STYLE SEGMENT LOOP }
do
{
// { get style run information for the current style run }
_WEGetIndStyle(runIndex, &runInfo, hWE);
runIndex = runIndex + 1;
// { calculate ascent and descent (actually, descent + leading) values for this style run }
runAscent = runInfo.runAttrs.runAscent;
runDescent = runInfo.runAttrs.runHeight - runAscent;
// { save the maximum values in lineAscent and lineDescent }
if (runAscent > *lineAscent)
{
*lineAscent = runAscent;
}
if (runDescent > *lineDescent)
{
*lineDescent = runDescent;
}
// { keep looping until we reach rangeEnd }
} while (runInfo.runEnd < rangeEnd);
}
OSErr _WERecalBreaks(long *startLine, long *endLine, WEHandle hWE)
{
// { Recalculates line breaks, line heights and ascents for all the text or for a portion of it. }
// { On entry, startLine and endLine define a range of lines to recalculate. }
// { On exit, startLine to endLine defines the range of lines actually recalculated }
// { the WE record must already be locked }
WEPtr pWE;
LinePtr pLine;
LineRec lineInfo, oldLineInfo;
long lineIndex;
long recalThreshold;
long lineOffset;
short lineAscent, lineDescent;
Boolean saveTextLock;
QDEnvironment saveEnvironment;
OSErr err;
OSErr retval;
retval = noErr;
pWE = *hWE;
// { lock the text }
saveTextLock = _WESetHandleLock(pWE->hText, true);
// { find the character offset that must be necessarily reached before we can }
// { even consider the possibility of stopping the recalculation process }
// { this offset, recalThreshold, is the last character on endLine _before_ recalculation }
lineIndex = _WEPinInRange(*endLine, 0, pWE->nLines - 1);
recalThreshold = (*pWE->hLines)[lineIndex + 1].lineStart;
// { we start recalculating line breaks from the line actually _preceding_ startLine, }
// { since editing startLine may cause part of its text to fit on the preceding line }
lineIndex = _WEPinInRange(*startLine - 1, 0, pWE->nLines - 1);
// { find where in the text recalculation should begin }
lineInfo = (*pWE->hLines)[lineIndex];
// { save the QuickDraw environment }
_WESaveQDEnvironment(pWE->port, false, &saveEnvironment);
// { MAIN LINE BREAKING LOOP }
do
{
// { find where to break the current line }
lineOffset = _WEFindLineBreak(lineInfo.lineStart, hWE);
// { calculate ascent and descent values for this line }
_WECalcHeights(lineInfo.lineStart, lineInfo.lineStart + lineOffset, &lineAscent, &lineDescent, hWE);
// { save the maximum line ascent for this line in the line array }
pLine = &(*pWE->hLines)[lineIndex];
pLine->lineAscent = lineAscent;
// { increment counters (go to the next line array entry) }
lineIndex = lineIndex + 1;
lineInfo.lineStart = lineInfo.lineStart + lineOffset;
lineInfo.lineOrigin = lineInfo.lineOrigin + (lineAscent + lineDescent);
pLine++;
// { compare the newly calculated line start with the old value }
// { if the new line start comes before the old line start, insert a new element }
oldLineInfo = *pLine;
if ((lineIndex > pWE->nLines) || (lineInfo.lineStart < oldLineInfo.lineStart))
{
err = InsertLine(lineIndex, &lineInfo, pWE);
// { clean up and exit if we ran out of memory }
if (err != noErr)
{
retval = err;
goto cleanup;
}
}
else
{
// { overwrite the old element }
pLine->lineStart = lineInfo.lineStart;
pLine->lineOrigin = lineInfo.lineOrigin;
// { remove all further elements which have a lineStart field }
// { less than or equal to the current one }
while((lineIndex + 1 <= pWE->nLines) &&
(lineInfo.lineStart >= (*pWE->hLines)[lineIndex + 1].lineStart))
{
err = _WERemoveLine(lineIndex + 1, pWE);
}
// { if the new line start is the same as the old one... }
if (lineInfo.lineStart == oldLineInfo.lineStart)
{
// { ...and recalThreshold has been reached, we can stop recalculating line breaks }
if (lineInfo.lineStart >= recalThreshold)
{
// { although line breaks need not be changed from lineIndex on, }
// { the lineOrigin fields may need to be changed }
if (lineInfo.lineOrigin != oldLineInfo.lineOrigin)
{
_WEBumpOrigin(lineIndex + 1, lineInfo.lineOrigin - oldLineInfo.lineOrigin, pWE);
}
// { exit from the line breaking loop }
goto cleanup;
}
}
else
{
// { otherwise, the new line start comes after the old line start... }
// { if the current line is the one preceding startLine, warn our caller about this }
if ((lineIndex > 0) && (lineIndex == *startLine))
{
*startLine = lineIndex - 1;
}
}
}
} while(lineInfo.lineStart < pWE->textLength);
cleanup:
// { set destRect.bottom to destRect.top + total text height }
pWE->destRect.bottom = pWE->destRect.top + WEGetHeight(0, pWE->nLines, hWE);
// { quirk: if the last character in the text is a carriage return, the caret appears }
// { below the last line, so in this case we need to add the extra height to destRect.bottom }
if (WEGetChar(pWE->textLength - 1, hWE) == '\r')
{
pWE->destRect.bottom = pWE->destRect.bottom +
WEGetHeight(pWE->nLines - 1, pWE->nLines, hWE);
}
// { return through endLine the index of the last line affected by recalculation }
*endLine = lineIndex - 1;
// { make sure startLine isn't greater than endLine }
if (*startLine > *endLine)
{
*startLine = *endLine;
}
// { unlock the text }
_WESetHandleLock(pWE->hText, saveTextLock);
// { restore the QuickDraw environment }
_WERestoreQDEnvironment(&saveEnvironment);
return retval;
}
Boolean SLCalcSlop(LinePtr pLine, WERunAttributesPtr pAttrs, Ptr pSegment, long segmentStart,
long segmentLength, JustStyleCode styleRunPosition, void *callbackData);
Boolean SLCalcSlop(LinePtr pLine, WERunAttributesPtr pAttrs, Ptr pSegment, long segmentStart,
long segmentLength, JustStyleCode styleRunPosition, void *callbackData)
{
Boolean isEndOfLine;
Boolean retval;
struct SLCalcSlopData *p = (struct SLCalcSlopData *) callbackData;
retval = false; // { keep looping }
// { see if this text segment ends with a carriage return, or if we've reached the }
// { end of the text (in which case we don't want any justification to take place) }
isEndOfLine = (segmentStart + segmentLength >= p->pWE->textLength) ||
( *((Ptr)pSegment + segmentLength - 1) == kEOL);
// { if this is the first segment on the line, reset line totals }
if (styleRunPosition <= smLeftStyleRun)
{
p->totalSlop = p->lineWidth;
p->totalProportion = 0;
}
// { if this is the last segment on the line, strip trailing spaces }
if (!(styleRunPosition & 1))
{
segmentLength = VisibleLength(pSegment, segmentLength);
}
// { measure this segment and subtract its width from totalSlop }
p->totalSlop = p->totalSlop - TextWidth(pSegment, 0, segmentLength);
// { calculate the proportion of extra space to apply to this text segment }
p->totalProportion = p->totalProportion + NPortionText(pSegment, segmentLength,
styleRunPosition, *(Point *)&kOneToOneScaling, *(Point *)&kOneToOneScaling);
// { if this is the last segment on the line, save values in the line array }
if (!(styleRunPosition & 1))
{
pLine->lineSlop = p->totalSlop;
if (isEndOfLine)
{
pLine->lineJustAmount = 0;
}
else
{
pLine->lineJustAmount = FixDiv(BSL(p->totalSlop, 16), p->totalProportion);
}
}
return retval;
}
void _WERecalSlops(long firstLine, long lastLine, WEHandle hWE)
{
// { Calculates the lineSlop and lineJustAmount fields }
// { of the line array for the specified lines }
WEPtr pWE;
short lineWidth;
struct SLCalcSlopData callbackData;
pWE = *hWE;
lineWidth = pWE->destRect.right - pWE->destRect.left;
// { calculate slop and normalized slop proportion for all lines }
callbackData.lineWidth = lineWidth;
callbackData.pWE = pWE;
_WESegmentLoop(firstLine, lastLine, SLCalcSlop, (void *) &callbackData, hWE);
}
pascal OSErr WECalText(WEHandle hWE)
{
long startLine, endLine;
Boolean saveWELock;
OSErr err;
// { lock WE record }
saveWELock = _WESetHandleLock((Handle)hWE, true);
// { recalculate all line breaks }
startLine = 0;
endLine = LONG_MAX;
err = _WERecalBreaks(&startLine, &endLine, hWE);
// { recalculate line slops }
if (err == noErr)
{
_WERecalSlops(startLine, endLine, hWE);
}
// { unlock the WE record }
_WESetHandleLock((Handle)hWE, saveWELock);
// { return result code }
return err;
}
pascal OSErr WEUseText(Handle text, WEHandle hWE)
{
WEPtr pWE;
long textLength;
Boolean saveWELock;
// { lock the WE record }
saveWELock = _WESetHandleLock((Handle)hWE, true);
pWE = *hWE;
// { install the text }
_WEForgetHandle((Handle *)&pWE->hText);
pWE->hText = text;
textLength = GetHandleSize(text);
pWE->textLength = textLength;
(*pWE->hRuns)[pWE->nRuns].runStart = textLength + 1;
(*pWE->hLines)[pWE->nLines].lineStart = textLength;
// { unlock the WE record }
_WESetHandleLock((Handle)hWE, saveWELock);
return noErr;
}
pascal char WEGetAlignment(WEHandle hWE)
{
return (*hWE)->alignment;
}
pascal void WEGetSelection(long *selStart, long *selEnd, WEHandle hWE)
{
WEPtr pWE;
pWE = *hWE;
*selStart = pWE->selStart;
*selEnd = pWE->selEnd;
}
pascal void WESetDestRect(LongRect *destRect, WEHandle hWE)
{
(*hWE)->destRect = *destRect;
}
pascal void WEGetDestRect(LongRect *destRect, WEHandle hWE)
{
*destRect = (*hWE)->destRect;
}
pascal void WESetViewRect(LongRect *viewRect, WEHandle hWE)
{
WEPtr pWE;
Rect r;
pWE = *hWE;
pWE->viewRect = *viewRect;
// { keep the viewRgn in sync with the view rectangle }
WELongRectToRect(viewRect, &r);
RectRgn(pWE->viewRgn, &r);
}
pascal void WEGetViewRect(LongRect *viewRect, WEHandle hWE)
{
*viewRect = (*hWE)->viewRect;
}
pascal long WEGetTextLength(WEHandle hWE)
{
return (*hWE)->textLength;
}
pascal long WECountLines(WEHandle hWE)
{
return (*hWE)->nLines;
}
pascal long WEGetHeight(long startLine, long endLine, WEHandle hWE)
{
WEPtr pWE;
LineArrayPtr pLines;
long nLines;
pWE = *hWE;
pLines = *pWE->hLines;
nLines = pWE->nLines;
startLine = _WEPinInRange(startLine, 0, nLines);
endLine = _WEPinInRange(endLine, 0, nLines);
_WEReorder(&startLine, &endLine);
return pLines[endLine].lineOrigin - pLines[startLine].lineOrigin;
}
pascal Handle WEGetText(WEHandle hWE)
{
return (*hWE)->hText;
}
pascal char WEGetChar(long offset, WEHandle hWE)
{
WEPtr pWE;
pWE = *hWE;
// { sanity check: make sure offset is withing allowed bounds }
if ((offset < 0) || (offset >= pWE->textLength))
{
return 0;
}
// { get the specified character (actually, byte) }
return (*pWE->hText)[offset];
}
pascal short WECharByte(long offset, WEHandle hWE)
{
WEPtr pWE;
WERunInfo info;
short saveFont;
GrafPtr savePort;
short byte;
pWE = *hWE;
// { exit now if there is no double-byte script system installed }
if (!BTST(pWE->flags, weFDoubleByte))
{
return smSingleByte;
}
// { sanity check: make sure offset is within allowed bounds }
if ((offset < 0) || (offset >= pWE->textLength))
{
return smSingleByte;
}
// { get style information associated with the specified offset }
WEGetRunInfo(offset, &info, hWE);
// { save the port }
GetPort(&savePort);
SetPort(pWE->port);
// { set the port font to the style run font }
saveFont = pWE->port->txFont;
TextFont(info.runAttrs.runStyle.tsFont);
// { pass CharByte a pointer to the beginning of the style run }
byte = CharByte((Ptr)(*pWE->hText) + info.runStart, offset - info.runStart);
// { restore the port font }
TextFont(saveFont);
// { restore the port }
SetPort(savePort);
return byte;
}
pascal short WECharType(long offset, WEHandle hWE)
{
WEPtr pWE;
WERunInfo info;
Handle hText;
short saveFont;
GrafPtr savePort;
Boolean saveTextLock;
short retval;
pWE = *hWE;
hText = pWE->hText;
// { sanity check: make sure offset is within allowed bounds }
if ((offset < 0) || (offset >= pWE->textLength))
{
return 0;
}
// { get style information associated with the specified offset }
WEGetRunInfo(offset, &info, hWE);
// { save the port }
GetPort(&savePort);
SetPort(pWE->port);
// { set the port font to the style run font }
saveFont = pWE->port->txFont;
TextFont(info.runAttrs.runStyle.tsFont);
// { lock the text (CharType may move memory) }
saveTextLock = _WESetHandleLock(hText, true);
// { pass CharType a pointer to the beginning of the style run }
retval = CharType((Ptr)*pWE->hText + info.runStart, offset - info.runStart);
// { unlock the text }
_WESetHandleLock(hText, saveTextLock);
// { restore the port font }
TextFont(saveFont);
// { restore the port }
SetPort(savePort);
return retval;
}
pascal OSErr WECopyRange(long rangeStart, long rangeEnd, Handle hText, WEStyleScrapHandle
hStyles, WEHandle hWE)
{
// { Make a copy of the specified range of text: store the characters in hText }
// { and the associated style scrap in hStyles. The handles are resized as necessary. }
// { Specify NIL in hText or hStyles if you don't want the corresponding info returned. }
WEPtr pWE;
long rangeLength;
long firstRun, nRuns, i;
long startChar;
WERunInfo info;
WEStyleScrapElementPtr pElement;
Boolean saveWELock;
OSErr err;
// { lock the WE record }
saveWELock = _WESetHandleLock((Handle)hWE, true);
pWE = *hWE;
// { range-check parameters and reorder them if necessary }
rangeStart = _WEPinInRange(rangeStart, 0, pWE->textLength);
rangeEnd = _WEPinInRange(rangeEnd, 0, pWE->textLength);
_WEReorder(&rangeStart, &rangeEnd);
rangeLength = rangeEnd - rangeStart;
if (hText != nil)
{
// { resize the given handle }
SetHandleSize(hText, rangeLength);
err = MemError();
if (err != noErr)
{
goto cleanup;
}
// { copy the text range }
BlockMoveData((Ptr)*pWE->hText + rangeStart, (Ptr)*hText, rangeLength);
}
if (hStyles != nil)
{
// { count how many style runs there are in the selection range }
firstRun = _WEOffsetToRun(rangeStart, hWE);
nRuns = _WEOffsetToRun(rangeEnd - 1, hWE) - firstRun + 1;
// { try to allocate a handle big enough to contain all these style runs }
// { resize the given handle }
SetHandleSize((Handle)hStyles, sizeof(short) + (nRuns * sizeof(ScrpSTElement)));
err = MemError();
if (err != noErr)
{
goto cleanup;
}
// { fill in the style count in the style scrap }
// { *** POTENTIAL PROBLEM: if nRuns > 32767, scrpNStyles will be invalid *** }
(*hStyles)->scrpNStyles = nRuns;
// { fill the style scrap }
pElement = &(*hStyles)->scrpStyleTab[0];
for(i = 0; i<nRuns; i++)
{
_WEGetIndStyle(firstRun + i, &info, hWE);
startChar = info.runStart - rangeStart;
if (startChar < 0)
{
startChar = 0;
}
pElement->scrpStartChar = startChar;
pElement->scrpAttrs = info.runAttrs;
pElement->scrpAttrs.runStyle.tsFlags = 0;
pElement++;
}
}
// { clear result code }
err = noErr;
cleanup:
// { unlock the WE record }
_WESetHandleLock((Handle)hWE, saveWELock);
// { return result code }
return err;
}
pascal OSErr WECopy(WEHandle hWE)
{
// { Copy the selection range to the desk scrap }
WEPtr pWE;
long selStart, selEnd;
Handle hText, hStyles;
OSErr err;
pWE = *hWE;
hText = nil;
hStyles = nil;
// { get selection range }
selStart = pWE->selStart;
selEnd = pWE->selEnd;
// { do nothing if the selection range is empty }
if (selStart < selEnd)
{
// { allocate two zero-length handles to hold a copy of the selection text and styles }
err = _WEAllocate(0, kAllocTemp, (Handle *)&hText);
if (err != noErr)
{
goto cleanup;
}
err = _WEAllocate(0, kAllocTemp, (Handle *)&hStyles);
if (err != noErr)
{
goto cleanup;
}
// { make a copy of the selection text and styles }
err = WECopyRange(selStart, selEnd, hText, (WEStyleScrapHandle)hStyles, hWE);
if (err != noErr)
{
goto cleanup;
}
// { clear the desk scrap }
err = ZeroScrap();
if (err != noErr)
{
goto cleanup;
}
// { put the text }
HLock(hText);
err = PutScrap(GetHandleSize(hText), kTypeText, *hText);
if (err != noErr)
{
goto cleanup;
}
HUnlock(hText);
// { put the styles }
HLock(hStyles);
err = PutScrap(GetHandleSize(hStyles), kTypeStyles, *hStyles);
if (err != noErr)
{
goto cleanup;
}
HUnlock(hStyles);
}
// { clear result code }
err = noErr;
cleanup:
// { clean up }
_WEForgetHandle((Handle *)&hText);
_WEForgetHandle((Handle *)&hStyles);
// { return result code }
return err;
}
pascal short WEFeatureFlag(short feature, short action, WEHandle hWE)
{
WEPtr pWE;
short retval;
pWE = *hWE;
// { return current status }
retval = BTST(pWE->flags, feature) ? weBitSet : weBitClear;
// { set new status if necessary }
if (action == weBitClear)
{
BCLR(pWE->flags, feature);
}
else if (action == weBitSet)
{
BSET(pWE->flags, feature);
}
return retval;
}
pascal OSErr WEGetInfo(OSType selector, Ptr info, WEHandle hWE)
{
switch(selector)
{
case 'clik':
*(long *)info = (long)(*hWE)->clickLoop;
return noErr;
case 'line':
*(long *)info = (long)(*hWE)->hLines;
return noErr;
case 'port':
*(long *)info = (long)(*hWE)->port;
return noErr;
case 'post':
*(long *)info = (long)(*hWE)->tsmPostUpdate;
return noErr;
case 'pre ':
*(long *)info = (long)(*hWE)->tsmPreUpdate;
return noErr;
case 'refc':
*(long *)info = (*hWE)->refCon;
return noErr;
case 'runa':
*(long *)info = (long)(*hWE)->hRuns;
return noErr;
case 'scrl':
*(long *)info = (long)(*hWE)->scrollProc;
return noErr;
case 'styl':
*(long *)info = (long)(*hWE)->hStyles;
return noErr;
case 'text':
*(long *)info = (long)(*hWE)->hText;
return noErr;
case 'tsmd':
*(long *)info = (long)(*hWE)->tsmReference;
return noErr;
}
return paramErr;
}
pascal OSErr WESetInfo(OSType selector, Ptr info, WEHandle hWE)
{
switch(selector)
{
case 'clik':
(*hWE)->clickLoop = (ProcPtr)*(long *)info;
return noErr;
case 'line':
(*hWE)->hLines = (LineArrayHandle)*(long *)info;
return noErr;
case 'port':
(*hWE)->port = (GrafPtr)*(long *)info;
return noErr;
case 'post':
(*hWE)->tsmPostUpdate = (ProcPtr)*(long *)info;
return noErr;
case 'pre ':
(*hWE)->tsmPreUpdate = (ProcPtr)*(long *)info;
return noErr;
case 'refc':
(*hWE)->refCon = *(long *)info;
return noErr;
case 'runa':
(*hWE)->hRuns = (RunArrayHandle)*(long *)info;
return noErr;
case 'scrl':
(*hWE)->scrollProc = (ProcPtr)*(long *)info;
return noErr;
case 'styl':
(*hWE)->hStyles = (StyleTableHandle)*(long *)info;
return noErr;
case 'text':
(*hWE)->hText = (Handle)*(long *)info;
return noErr;
case 'tsmd':
(*hWE)->tsmReference = (TSMDocumentID)*(long *)info;
return noErr;
}
return paramErr;
}